<?php
/**
 * This class is a blueprint for containers, it provides functionality for containers to have children
 * and to iterate through those children.
 *
 * @author Niels Janssen
 * @since 2008-07-08
 * @package Form
 */
abstract class FormContainer extends FormNode implements ArrayAccess, Iterator {

	/**
	 * An array of all the children of this node.
	 *
	 * @var FormNode[]
	 */

	protected $children = array ();

	/**
	 *
	 */
	function __construct( $name, array $properties = array() ) {
		parent::__construct( $name, $properties );
	}

	/**
	 * Adds a child to this container. The child must be of the type FormNode but cannot be a Form instance.
	 * It also cannot be the same as itself, because else infinite recursion could occur.
	 * It allows for an accessible name to be given, to allow associative array access to the child.
	 *
	 * @param FormNode $child
	 * @param String $accessName
	 */
	public function addChild( FormNode $child, $accessName = '' ) {
		if( $child instanceof Form ) {
			throw new FormException( "The form cannot be added as a child, as it is the root node" );
		}

		if( $child === $this ) {
			throw new FormException( "An element can not be added as its own child" );
		}

		if( $child == NULL )
		{
			return;
		}
		
		if( empty( $accessName ) )
		{
			if(class_exists( 'Checkbox' ) && $child instanceof Checkbox )
			{
				if( isset( $this->children[ $child->getProperty('name') ] ) && $this->children[ $child->getProperty('name') ] instanceof Checkbox )
				{
					$name = $child->getProperty('name') . '_' . count( $this->children );
				}
				else
				{
					$name = $child->getProperty('name') != '' ? $child->getProperty('name') : count( $this->children ); 
				}
				
			}
			else 
			{
				$name = $child->getProperty('name') != '' ? $child->getProperty('name') : count( $this->children ); 
			}
		}
		else
			$name = $accessName;

		$this->children [ $name ] = $child;
		
		$child->setParent( $this );
	}

	public function addChildren( array $children ) {
		foreach( $children as $child ) {
			$this->addChild( $child );
		}
	}

	public function getChildren() {
		return $this->children;
	}

	public function removeChild( FormNode $remove ) {
		foreach( $this->children as &$child ) {
			if( $child === $remove ) {
				$child = null;
			}
		}
	}

	/**
	 * Returns wether or not this container has children.
	 *
	 * @return boolean
	 */
	public function hasChildren( ) {
		return count( $this->children ) > 0;
	}

	public function isValid( ) {
		$valid = true;

		if( $this->hasChildren() ) {
			foreach( $this->children as $child ) {
				if( $child != null )
					$valid = $child->isValid() && $valid;
			}
		}

		return $valid;
	}

	public function compareTo( FormNode $fn ) {
		return $this === $fn;
	}
	
	public function offsetGet( $key )
	{
		return isset( $this->children[ $key ] ) ? $this->children[ $key ] : null;
	}
	
	public function offsetExists( $key )
	{
		return isset( $this->children[ $key ] );
	}
	
	public function offsetUnset( $key ){}
	public function offsetSet( $key, $value ) {}
	
	
    public function rewind() {
        reset($this->children);
    }

    public function current() {
        return current($this->children);
    }

    public function key() {
        return key($this->children);
    }

    public function next() {
        return next($this->children);
    }

    public function valid() {
        return $this->current() !== false;
    }
}

?>